//
// Created by Administrator on 2021/8/31.
//

#ifndef OPENGLLEARN_APP_H
#define OPENGLLEARN_APP_H

#include "Application/Application.h"
#include "FileUtils.h"
#include "Shader/ShaderProgram.h"
#include "Geometry/Matrix4x4.h"

class App : public Application
{
protected:
    void OnCreate() override
    {
        static const GLfloat position[] = {
                -0.3f, 0.0f,
                0.3f, 0.0f,
                -0.20f, 1.0f,
                0.1f, 1.3f,
                -0.05f, 2.3f,
                0.0f, 3.3f
        };

        ShaderInfo info("../../Chapter7/res/vert.glsl", "../../Chapter7/res/frag.glsl");
        sp_ = ShaderProgram(info);

        glCreateVertexArrays(1, &vao_);
        glBindVertexArray(vao_);

        glCreateBuffers(1, &vbo_);
        glBindBuffer(GL_ARRAY_BUFFER, vbo_);
        glBufferData(GL_ARRAY_BUFFER, sizeof position, position, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
        glEnableVertexAttribArray(0);

        glCreateTextures(GL_TEXTURE_2D, 1, &tex_);
        glTextureStorage2D(tex_, 1, GL_RGBA32F, 1024, 1024);
        auto* texture = new GLfloat [1024 * 1024 * 4];
        for(auto j = 0; j < 1024; ++j)
        {
            for(auto i = 0; i < 1024; ++i)
            {
                texture[(j * 1024 + i) * 4] = static_cast<float>(GetRandom((j * 1024 + i) * 4, 2) & 0xff) / 256.0f;
                texture[(j * 1024 + i) * 4 + 1] = static_cast<float>(GetRandom((j * 1024 + i) * 4 + 1, 3) & 0xff) / 256.0f * 360 * DEG_2_RAD;
                texture[(j * 1024 + i) * 4 + 2] = static_cast<float>(GetRandom((j * 1024 + i) * 4 + 2, 4) & 0xff) / 512.0f * 180 * DEG_2_RAD;
                texture[(j * 1024 + i) * 4 + 3] = 0.0f;
            }
        }
        glTextureSubImage2D(tex_, 0, 0, 0, 1024, 1024, GL_RGBA, GL_FLOAT, texture);
        glBindTextureUnit(0, tex_);
        delete[] texture;
    }

    void OnRender() override
    {
        static const GLfloat bgColor[] = {0.1f, 0.1f, 0.1f, 1.0f};
        glClearBufferfv(GL_COLOR, 0, bgColor);

        sp_.Use();
        GLfloat data[16];
        auto mvpMatrix = projectMatrix * cameraMatrix;
        mvpMatrix.GetData(data);
        sp_.SetMatrix4("_MvpMatrix", data);

        glBindVertexArray(vao_);
        glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 6, 1024 * 1024);
    }

    void OnDestroy() override
    {
        glDeleteVertexArrays(1, &vao_);
        glDeleteBuffers(1, &vbo_);
        glDeleteTextures(1, &tex_);
    }

private:
    static int GetRandom(int seed, int iteractions)
    {
        auto value = seed;
        for(auto i = 0; i < iteractions; ++i)
        {
            value = ((value >> 7) ^ (value << 9)) * 15485863;
        }

        return value;
    }

    GLuint vao_;
    GLuint vbo_;
    GLuint tex_;
    ShaderProgram sp_;
};

#endif //OPENGLLEARN_APP_H
